#!/usr/bin/env python3
"""
Script to find unmatched \left and \right commands that could cause 
progressive indentation by creating unclosed groups.
"""
import os
import re
import glob

def check_left_right_balance(filepath):
    """Check for unmatched \\left and \\right commands in a file."""
    try:
        with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
            content = f.read()
    except Exception as e:
        return {'error': str(e)}
    
    lines = content.split('\n')
    
    # Track \left and \right commands
    left_commands = []
    right_commands = []
    unmatched_lefts = []
    
    for i, line in enumerate(lines, 1):
        # Find all \left commands on this line
        lefts = re.finditer(r'\\left[^a-zA-Z]', line)
        for match in lefts:
            left_commands.append((i, match.start(), line.strip()))
        
        # Find all \right commands on this line  
        rights = re.finditer(r'\\right[^a-zA-Z]', line)
        for match in rights:
            right_commands.append((i, match.start(), line.strip()))
    
    # Simple balance check
    balance = len(left_commands) - len(right_commands)
    
    # More sophisticated matching within math environments
    # Track nested levels
    left_stack = []
    unmatched = []
    
    # Process line by line to track nesting
    for i, line in enumerate(lines, 1):
        # Find \left and \right in order they appear
        lefts = [(m.start(), 'left', m.group()) for m in re.finditer(r'\\left[^a-zA-Z]', line)]
        rights = [(m.start(), 'right', m.group()) for m in re.finditer(r'\\right[^a-zA-Z]', line)]
        
        # Combine and sort by position
        all_commands = sorted(lefts + rights, key=lambda x: x[0])
        
        for pos, cmd_type, cmd_text in all_commands:
            if cmd_type == 'left':
                left_stack.append((i, pos, cmd_text, line.strip()))
            elif cmd_type == 'right':
                if left_stack:
                    left_stack.pop()  # Match found
                else:
                    unmatched.append((i, pos, 'extra_right', cmd_text, line.strip()))
    
    # Any remaining in left_stack are unmatched lefts
    for line_num, pos, cmd_text, line_content in left_stack:
        unmatched.append((line_num, pos, 'unmatched_left', cmd_text, line_content))
    
    return {
        'file': filepath,
        'left_count': len(left_commands),
        'right_count': len(right_commands),
        'balance': balance,
        'unmatched': unmatched,
        'left_details': left_commands[:5],  # First 5 for debugging
        'right_details': right_commands[:5]
    }

def check_cases_environment(filepath):
    """Check for unmatched cases, aligned, etc. environments that use \\left\\{ \\right."""
    try:
        with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
            content = f.read()
    except Exception as e:
        return {'error': str(e)}
    
    issues = []
    
    # Look for specific problematic patterns
    patterns = [
        (r'\\left\\{', r'\\right\\}', 'left/right braces'),
        (r'\\left\(', r'\\right\)', 'left/right parentheses'),
        (r'\\left\[', r'\\right\]', 'left/right brackets'),
        (r'\\begin\{cases\}', r'\\end\{cases\}', 'cases environment'),
        (r'\\begin\{aligned\}', r'\\end\{aligned\}', 'aligned environment'),
        (r'\\begin\{align\}', r'\\end\{align\}', 'align environment')
    ]
    
    for left_pattern, right_pattern, desc in patterns:
        lefts = len(re.findall(left_pattern, content))
        rights = len(re.findall(right_pattern, content))
        
        if lefts != rights:
            issues.append({
                'type': desc,
                'left_count': lefts,
                'right_count': rights,
                'balance': lefts - rights
            })
    
    return {
        'file': filepath,
        'issues': issues
    }

def main():
    # Check all .tex files
    tex_files = glob.glob('part*/*.tex', recursive=True)
    tex_files.sort()
    
    print("=" * 80)
    print("LaTeX \\left/\\right Balance Analysis")
    print("=" * 80)
    
    total_imbalance = 0
    problematic_files = []
    
    for tex_file in tex_files:
        if os.path.exists(tex_file):
            result = check_left_right_balance(tex_file)
            case_result = check_cases_environment(tex_file)
            
            if 'error' in result:
                print(f"❌ Error reading {tex_file}: {result['error']}")
                continue
            
            file_has_problems = False
            
            # Check basic left/right balance
            if result['balance'] != 0:
                problematic_files.append(result)
                total_imbalance += result['balance']
                file_has_problems = True
                print(f"\n⚠️  \\left/\\right IMBALANCE in {result['file']}:")
                print(f"   \\left commands: {result['left_count']}")
                print(f"   \\right commands: {result['right_count']}")
                print(f"   Balance: {result['balance']:+d}")
            
            # Check for specific unmatched commands
            if result['unmatched']:
                file_has_problems = True
                print(f"\n🔥 UNMATCHED COMMANDS in {result['file']}:")
                for line_num, pos, issue_type, cmd, line_content in result['unmatched']:
                    print(f"   Line {line_num}: {issue_type} - {cmd}")
                    print(f"      Content: {line_content}")
            
            # Check special environments
            if case_result['issues']:
                file_has_problems = True
                print(f"\n⚠️  ENVIRONMENT ISSUES in {result['file']}:")
                for issue in case_result['issues']:
                    print(f"   {issue['type']}: {issue['balance']:+d} (left={issue['left_count']}, right={issue['right_count']})")
            
            if not file_has_problems:
                print(f"✓ {result['file']} - OK (\\left: {result['left_count']}, \\right: {result['right_count']})")
    
    print("\n" + "=" * 80)
    print("SUMMARY:")
    print("=" * 80)
    print(f"Files checked: {len(tex_files)}")
    print(f"Files with \\left/\\right imbalances: {len(problematic_files)}")
    print(f"Total cumulative \\left/\\right imbalance: {total_imbalance:+d}")
    
    if total_imbalance > 0:
        print(f"\n🔥 CRITICAL: {total_imbalance} unclosed \\left commands!")
        print("This creates unclosed groups that accumulate through the document.")
        print("Each unclosed \\left creates a group that adds permanent left indentation.")
    elif total_imbalance < 0:
        print(f"\n🔥 CRITICAL: {abs(total_imbalance)} extra \\right commands!")
        print("This indicates improperly structured math environments.")
    else:
        print(f"\n✅ All \\left/\\right commands are balanced.")
    
    print("=" * 80)

if __name__ == "__main__":
    main()